package com.cheetah.handler;

import com.cheetah.annotation.Handler;
import com.cheetah.constants.AttributeKeyConstants;
import com.cheetah.constants.ProtocolConstants;
import com.cheetah.protocol.CheetahMessage;
import com.cheetah.protocol.ErrorCode;
import com.cheetah.protocol.ResponseBuilder;
import com.cheetah.protostuff.ProtostuffSerialization;
import io.netty.channel.*;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.net.SocketAddress;

/**
 * @Author Administrator
 * @Date 2019/9/17
 * @Version V1.0
 * @Description: 全局异常处理
 **/
@Component
@Handler(order = Integer.MAX_VALUE,sharable = true)
@Slf4j
@ChannelHandler.Sharable
public class ExceptionHandler extends ChannelDuplexHandler {

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {

        log.error(cause.getMessage(),cause);
        byte[] data = ProtostuffSerialization.serialize(ResponseBuilder.builder().fail(ErrorCode.ERROR_CODE_500, cause.getMessage()));
        String type = (String)ctx.channel().attr(AttributeKey.valueOf(AttributeKeyConstants.ATTRIBUTE_KEY_TYPE)).get();
        ctx.channel().writeAndFlush(CheetahMessage.builder()
                .magic(ProtocolConstants.PROTOCOL_MAGIC_PROTO)
                .version(ProtocolConstants.PROTOCOL_VERSION_PROTO)
                .type(type)
                .flag(ProtocolConstants.PROTOCOL_FlAG_PROTO_1)
//                .headLen(0)
                .bodyLen(data.length)
                .data(data)
                .build());
    }

    @Override
    public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
        ctx.connect(remoteAddress, localAddress, promise.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) {
                if (!future.isSuccess()) {
                    log.error("connect fail!");
                }
            }
        }));
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        ctx.write(msg, promise.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) {
                if (!future.isSuccess()) {
                    log.error("write fail!");
                }
            }
        }));
    }
}
